
#include <level/level.hpp>
#include <rapidxml/rapidxml.hpp>
#include <resource_cache/resource_cache.hpp>
#include <window/window.hpp>
#include <boost/shared_array.hpp>
#include <fstream>
#include <nmn/create_string.hpp>
#include <iomanip>

level::level( std::string const & filename )
	:		m_time( 0.0f )
{
	std::ifstream file( filename.c_str( ) );

	if ( !file.is_open( ) )
	{
		throw std::runtime_error( filename + " could not be opened." );
	}

	file.seekg( 0, std::ios::end );
	size_t length = static_cast<size_t>( file.tellg( ) );
	file.seekg( 0, std::ios::beg );

	boost::shared_array< char > text( new char[ length + 1 ] );
	memset( text.get( ), 0, sizeof( char ) * ( length + 1 ) );

	file.read( text.get( ), length );

	rapidxml::xml_document<> document; document.parse<0>( text.get( ) );
	rapidxml::xml_node<> * level_node = document.first_node( "level" );
	if ( level_node == nullptr )
	{
		throw std::runtime_error( filename + " is invalid." );
	}

	boost::unordered_map< std::string, size_t > slides_by_name;

	for (	rapidxml::xml_node<> * slide_node = level_node->first_node( "slide" );
			slide_node != nullptr;
			slide_node = slide_node->next_sibling( slide_node->name( ) ) )
	{
		m_slides.push_back( slide_ptr( new slide( slide_node ) ) );
		slides_by_name[ slide_node->first_attribute( "name" )->value( ) ] = m_slides.size( ) - 1;
	}

	if ( m_slides.empty( ) )
	{
		throw std::runtime_error( filename + " is invalid." );
	}

	rapidxml::xml_node<> * start_node = level_node->first_node( "start" );
	m_active = slides_by_name[ start_node->first_node( "slide" )->first_attribute( "name" )->value( ) ];
	m_player.add_to_world(	m_slides[ m_active ]->world( ),
							g_inv_scale_b2_position * from_string<b2Vec2>( start_node->first_node( "position" )->value( ) ) );


	sf::Image * hud_image = g_cache.load_image( "./resources/images/level/hud.tga" );
	m_hud = sprite_ptr( new sf::Sprite( ) );
	m_hud->SetImage( *hud_image );
	m_hud->SetPosition( 800.0f, 0.0f );
}

void level::step( float delta_time )
{
	std::for_each( m_slides.begin( ), m_slides.end( ), [&delta_time]( slide_ptr s )
	{
		s->step( delta_time );
	} );

	m_player.step( delta_time );

	m_time += delta_time;
}

void level::draw( )
{
	m_slides[m_active]->draw( );
	m_player.draw( );
	g_window->Draw( *m_hud );

	sf::String time( nmn::create_string( "%1%", boost::io::group( std::fixed, std::setprecision(1), m_time ) ) );
	time.SetColor( sf::Color::Black );
	time.SetPosition( 900.0f, 110.0f );

	sf::String things( nmn::create_string( "%1%", m_player.things( ) ) );
	things.SetColor( sf::Color::Black );
	things.SetPosition( 900.0f, 210.0f );

	g_window->Draw( time );
	g_window->Draw( things );
}
